package com.github.yoojia.flow.at;

import com.github.yoojia.flow.Context;
import com.github.yoojia.flow.Event;
import com.github.yoojia.flow.support.CheckedEventInterceptor;

import java.util.HashMap;
import java.util.Map;

/**
 * @author 2017 Yoojia Chen (yoojiachen@gmail.com)
 */
public class AtSystemInterceptor extends CheckedEventInterceptor {

    private final Map<String, AtHandler> mHandlerMap = new HashMap<>();

    private static final byte[] REPLY_UNKNOWN_CMD = ATEvents.error("UNKNOWN_CMD").getBytes();
    private static final byte[] REPLY_ERROR = ATEvents.error("ERROR").getBytes();

    public AtSystemInterceptor() {
        mHandlerMap.put(ATEvents.CMD_MEM, new MemoryHandlerImpl());
        mHandlerMap.put(ATEvents.CMD_CPU, new CpuHandlerImpl());
        mHandlerMap.put(ATEvents.CMD_VER, new VersionHandlerImpl());
    }

    /**
     * 处理内部系统事件
     *
     * @param event Event
     * @return 符合内部事件
     */
    @Override
    protected boolean onIfAcceptEvent(Event event) {
        // 1. TOPIC
        // 2. DestAddress
        return ATEvents.AT_SYS_TOPIC.equals(event.topic) &&
                ATEvents.AT_SYS_ADDRESS.equals(event.destAddress);
    }

    @Override
    protected boolean onInterceptEventImpl(Context context, Event event) {
        try {
            handleAtRequest(context, event);
        } catch (Throwable throwable) {
            context.publishEvent(
                    createEvent(
                            REPLY_ERROR,
                            event.topic,
                            ATEvents.AT_SYS_ADDRESS,
                            event.sourceAddress));
        }
        return true;
    }

    private void handleAtRequest(Context context, Event event) {
        final String text = event.getTextPayload().getText();
        byte[] bytes;
        if (text.isEmpty() || !text.startsWith(ATEvents.AT)) {
            bytes = REPLY_UNKNOWN_CMD;
        } else {
            final String atName = parseAT(text);
            final AtHandler handler = mHandlerMap.get(atName);
            if (handler != null) {
                final String ret = handler.handle();
                if (ret == null || ret.isEmpty()) {
                    throw new IllegalArgumentException("AtHandler return EMPTY/NULL response");
                }
                bytes = ret.getBytes();
            } else {
                bytes = REPLY_UNKNOWN_CMD;
            }
        }
        context.publishEvent(
                Event.create(
                        getContext().nextSequenceId(),
                        bytes,
                        event.topic,
                        ATEvents.AT_SYS_ADDRESS,
                        event.sourceAddress,
                        System.currentTimeMillis()));
    }

    private String parseAT(String text) {
        return text.substring(3);
    }

}
